package com.demo.controller.admin;

import com.demo.dao.VenueDao;
import com.demo.entity.Venue;
import com.demo.service.VenueService;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.http.MediaType;
import org.springframework.mock.web.MockMultipartFile;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import org.springframework.transaction.annotation.Transactional;

import java.util.stream.IntStream;

import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.verify;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;

@SpringBootTest
@AutoConfigureMockMvc
@ActiveProfiles("test") // 使用测试配置文件
@Transactional // 测试后事务回滚
public class AdminVenueControllerIT {

    @Autowired
    private MockMvc mockMvc;

    @Autowired
    private VenueService venueService;

    @Autowired
    private VenueDao venueDao;

    private static final int TOTAL_VENUES = 50;

    @BeforeEach
    void setUp() {
        // 清空现有数据
        venueDao.deleteAll();

        // 生成 50 个场地数据
        IntStream.rangeClosed(1, TOTAL_VENUES).forEach(i -> {
            Venue venue = new Venue(
                    i,  // venueID
                    "Venue" + i,
                    "场地描述" + i,
                    100 + i,  // 价格
                    "venue" + i + ".jpg",  // 图片路径
                    "地址" + i,
                    "08:00",  // 开放时间
                    "22:00"   // 关闭时间
            );
            venueDao.save(venue);
        });

        // 验证数据插入
        assertAll(
                () -> assertEquals(TOTAL_VENUES, venueDao.count(), "总场地数量不匹配")
        );
    }

    @Test
    public void venueManage_ShouldReturnViewWithTotalPages0() throws Exception {

        mockMvc.perform(MockMvcRequestBuilders.get("/venue_manage"))
                .andExpect(status().isOk())
                .andExpect(view().name("admin/venue_manage"))
                .andExpect(model().attribute("total", 5));
    }

    @Test
    public void venueManage_ShouldReturnViewWithTotalPages1() throws Exception {
        int venueID = venueService.findAll().get(0).getVenueID();
        venueService.delById(venueID);


        mockMvc.perform(MockMvcRequestBuilders.get("/venue_manage"))
                .andExpect(status().isOk())
                .andExpect(view().name("admin/venue_manage"))
                .andExpect(model().attribute("total", 5));
    }

    @Test
    public void venueManage_ShouldReturnViewWithTotalPages2() throws Exception {
        Venue venue = new Venue(51, "场地名称51",
                "场地描述51",
                151,  // 价格
                "venue51" + ".jpg",  // 图片路径
                "地址51",
                "08:00",  // 开放时间
                "22:00");

        venueDao.save(venue);

        mockMvc.perform(MockMvcRequestBuilders.get("/venue_manage"))
                .andExpect(status().isOk())
                .andExpect(view().name("admin/venue_manage"))
                .andExpect(model().attribute("total", 6));
    }

    @Test
    public void venueEdit_ShouldReturnEditViewWithVenue() throws Exception {
        int venueID = venueService.findAll().get(0).getVenueID();
        Venue venue = venueService.findByVenueID(venueID);

        mockMvc.perform(MockMvcRequestBuilders.get("/venue_edit")
                        .param("venueID", String.valueOf(venueID)))
                .andExpect(status().isOk())
                .andExpect(view().name("/admin/venue_edit"))
                .andExpect(model().attribute("venue", venue));
    }

    @Test
    public void venueAdd_ShouldReturnAddView() throws Exception {
        mockMvc.perform(MockMvcRequestBuilders.get("/venue_add"))
                .andExpect(status().isOk())
                .andExpect(view().name("/admin/venue_add"));
    }

    @Test
    public void getVenueList_ShouldReturnPaginatedVenues0() throws Exception {

        mockMvc.perform(MockMvcRequestBuilders.get("/venueList.do")
                        .param("page", "1")) // 注意：Controller 中 page 从 1 开始
                .andExpect(status().isOk())
                .andExpect(jsonPath("$[0].venueName").value("Venue1"))
                .andExpect(jsonPath("$[1].price").value(102));
    }

    @Test
    public void getVenueList_ShouldReturnPaginatedVenues1() throws Exception {

        mockMvc.perform(MockMvcRequestBuilders.get("/venueList.do")) // 注意：Controller 中 page 从 1 开始
                .andExpect(status().isOk())
                .andExpect(jsonPath("$[0].venueName").value("Venue1"))
                .andExpect(jsonPath("$[1].price").value(102));
    }

    @Test
    public void getVenueList_ShouldReturnPaginatedVenues2() throws Exception {

        mockMvc.perform(MockMvcRequestBuilders.get("/venueList.do")
                        .param("page", "3")) // 注意：Controller 中 page 从 3 开始
                .andExpect(status().isOk())
                .andExpect(jsonPath("$[0].venueName").value("Venue21"))
                .andExpect(jsonPath("$[9].price").value(130));
    }

    @Test
    public void checkVenueName_ShouldReturnTrueWhenNameNotExist0() throws Exception {
        String venueName = "New Venue";

        mockMvc.perform(MockMvcRequestBuilders.post("/checkVenueName.do")
                        .param("venueName", venueName))
                .andExpect(status().isOk())
                .andExpect(content().string("true"));
    }

    @Test
    public void checkVenueName_ShouldReturnFalseWhenNameExists() throws Exception {
        String venueName = "Venue1";

        mockMvc.perform(MockMvcRequestBuilders.post("/checkVenueName.do")
                        .param("venueName", venueName))
                .andExpect(status().isOk())
                .andExpect(content().string("false"));
    }

    @Test
    public void addVenue_ShouldSaveVenueAndRedirect0() throws Exception {
        MockMultipartFile picture = new MockMultipartFile(
                "picture",
                "test.jpg",
                "image/jpeg",
                "test image content".getBytes()
        );

        mockMvc.perform(MockMvcRequestBuilders.multipart("/addVenue.do")
                        .file(picture)
                        .param("venueName", "Test Venue")
                        .param("address", "123 Street")
                        .param("description", "Test Description")
                        .param("price", "100")
                        .param("open_time", "08:00")
                        .param("close_time", "22:00")
                        .contentType(MediaType.MULTIPART_FORM_DATA))
                .andExpect(status().is3xxRedirection())
                .andExpect(redirectedUrl("venue_manage"));

        Venue savedVenue = venueService.findByVenueName("Test Venue");
        assertNotNull(savedVenue, "场地未成功保存到数据库");  // 确保场地数据已经被保存
        assertEquals("Test Venue", savedVenue.getVenueName(), "场地名称不匹配");
        assertEquals("123 Street", savedVenue.getAddress(), "场地地址不匹配");
        assertEquals("Test Description", savedVenue.getDescription(), "场地描述不匹配");
        assertEquals(100, savedVenue.getPrice(), "场地价格不匹配");
    }

    @Test
    public void addVenue_ShouldSaveVenueAndRedirect1() throws Exception {
        MockMultipartFile picture = new MockMultipartFile(
                "picture",
                "test.jpg",
                "image/jpeg",
                "test image content".getBytes()
        );

        mockMvc.perform(MockMvcRequestBuilders.multipart("/addVenue.do")
                        .file(picture)
                        .param("venueName", "Test Venue")
                        .param("address", "123 Street")
                        .param("description", "Test Description")
                        .param("price", "-100")
                        .param("open_time", "08:00")
                        .param("close_time", "22:00")
                        .contentType(MediaType.MULTIPART_FORM_DATA))
                .andExpect(status().is3xxRedirection())
                .andExpect(redirectedUrl("venue_add"));

        Venue savedVenue = venueService.findByVenueName("Test Venue");
        assertNull(savedVenue, "场地不应该保存到数据库");  // 确保场地数据已经被保存
    }


    @Test
    public void modifyVenue_ShouldUpdateVenueAndRedirect() throws Exception {
        int venueID = venueService.findAll().get(0).getVenueID();

        MockMultipartFile newFile = new MockMultipartFile(
                "picture",
                "new.jpg",
                "image/jpeg",
                "New Image".getBytes()
        );

        mockMvc.perform(MockMvcRequestBuilders.multipart("/modifyVenue.do")
                        .file(newFile)
                        .param("venueID", String.valueOf(venueID))
                        .param("venueName", "Updated Venue")
                        .param("address", "Updated Address")
                        .param("description", "Updated Desc")
                        .param("price", "200")
                        .param("open_time", "10:00")
                        .param("close_time", "22:00"))
                .andExpect(status().is3xxRedirection())
                .andExpect(redirectedUrl("venue_manage"));

        assertEquals("Updated Venue", venueService.findByVenueID(venueID).getVenueName());
        assertEquals("Updated Address", venueService.findByVenueID(venueID).getAddress());
    }

    @Test
    public void delVenue_ShouldDeleteVenueAndReturnTrue() throws Exception {
        int venueID = venueService.findAll().get(0).getVenueID();

        mockMvc.perform(MockMvcRequestBuilders.post("/delVenue.do")
                        .param("venueID", String.valueOf(venueID)))
                .andExpect(status().isOk())
                .andExpect(content().string("true"));

    }
}
